﻿using MiniFox.Components.Configurations;
using MiniFox.Exceptions;
using System.Globalization;
using System.Reflection;

namespace MiniFox.Components
{
    /// <summary>
    /// 
    /// </summary>
    public abstract class ComponentBuilder
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="componentConfig"></param>
        protected ComponentBuilder(IComponentConfig componentConfig)
        {
            this.ContractType = Type.GetType(componentConfig.ContractType);
            this.DefaultProvider = componentConfig.DefaultProvider;
            this.Providers = componentConfig.Providers;
        }
        /// <summary>
        /// 
        /// </summary>
        public string DefaultProvider
        {
            get;
        }
        /// <summary>
        /// 接口类型
        /// </summary>
        public Type ContractType
        {
            get;
        }
        /// <summary>
        /// 
        /// </summary>
        public ComponentProviderCollection Providers
        {
            get ;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected internal object ResolveComponentBySpare(params object[] args)
        {
            var attr = this.ContractType.GetCustomAttribute<SpareComponentAttribute>();
            if (attr == null)
                return null;

            Type type = attr.Type;
            if (!this.ContractType.IsAssignableFrom(type))
                throw new InvalidOperationException(string.Format(Resources.CommonMessages.EXPTN_ComponentConfig, this.ContractType.FullName, type.FullName));

            return Activator.CreateInstance(type, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, Type.DefaultBinder, args, CultureInfo.CurrentCulture);
        }
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="args"></param>
        ///// <returns></returns>
        //protected internal object ResolveComponentByConfig()
        //{
        //    return ConfigurationFactory.GetConfig(this.ContractType);
        //}
        /// <summary>
        /// 
        /// </summary>
        /// <param name="componentName"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public virtual object ResolveComponentByName(string componentName, params object[] args)
        {
            try
            {
                componentName = string.IsNullOrWhiteSpace(componentName) ? this.DefaultProvider : componentName;
                object instance = null;
                if (!string.IsNullOrWhiteSpace(componentName))
                {
                    instance = this.CreateComponent(componentName, args);
                }

                if (instance == null)
                {
                    instance = ResolveComponentBySpare(args);
                }

                //if (instance == null)
                //{
                //    instance = ResolveComponentByConfig();
                //}

                return instance;
            }
            catch (Exception e)
            {
                throw new ComponentBuildingException(this.ContractType.FullName, componentName, e, args);
            }

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="componentName"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public abstract object CreateComponent(string componentName, params object[] args);
    }
}
